/*
 * Copyright (c) 2016. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
 * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
 * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
 * Vestibulum commodo. Ut rhoncus gravida arcu.
 */

package com.tsinghuabigdata.edu.ddmath.commons.http;

import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;

import com.android.volley.RequestQueue;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.tsinghuabigdata.edu.commons.http.HttpRequest;
import com.tsinghuabigdata.edu.commons.http.HttpRequestException;
import com.tsinghuabigdata.edu.commons.http.VolleyHttpRequest;
import com.tsinghuabigdata.edu.commons.network.DNSHelper;
import com.tsinghuabigdata.edu.ddmath.ZxApplication;
import com.tsinghuabigdata.edu.ddmath.activity.RoboForActionBarActivity;
import com.tsinghuabigdata.edu.ddmath.constant.AppConst;
import com.tsinghuabigdata.edu.ddmath.constant.AppRequestConst;
import com.tsinghuabigdata.edu.ddmath.constant.BaseConfig;
import com.tsinghuabigdata.edu.ddmath.constant.ErrTag;
import com.tsinghuabigdata.edu.ddmath.util.AccountUtils;
import com.tsinghuabigdata.edu.ddmath.util.AppLog;
import com.tsinghuabigdata.edu.ddmath.util.AppUtils;
import com.tsinghuabigdata.edu.ddmath.util.PreferencesUtils;
import com.tsinghuabigdata.edu.utils.RestfulUtils;
import com.umeng.analytics.MobclickAgent;

import org.json.JSONException;
import org.json.JSONObject;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.List;

import au.id.villar.dns.DnsException;
import au.id.villar.dns.engine.Utils;
import roboguice.util.Strings;


/**
 * <p>
 * Created by yanshen@tsinghuabigdata.com on 2015/11/21.
 * </p>
 *
 * @author yanshen@tsinghuabigdata.com
 * @version V1.0
 * @packageName: com.tsinghuabigdata.edu.ddmath.commons.http
 * @createTime: 2015/11/21 14:15
 */
public class AppRequest<RESULT> extends VolleyHttpRequest {

    //private static Logger logger = Logger.getLogger("AppRequest");

//    public static void initLog4j() {
//        RollingFileAppender rollingFileAppender;
//        Layout fileLayout = new PatternLayout("%d %-5p [%c{2}]-[%L] %m%n");
//
//        try {
//            rollingFileAppender = new RollingFileAppender(fileLayout, Environment.getExternalStorageDirectory()
//                    + File.separator + "zxapp" + File.separator + "logs"
//                    + File.separator + "request.txt");
//        } catch (IOException e) {
//            throw new RuntimeException("Exception configuring log system", e);
//        }
//
//        rollingFileAppender.setMaxBackupIndex(5);
//        rollingFileAppender.setMaximumFileSize(1024 * 1024 * 5);
//        rollingFileAppender.setImmediateFlush(true);
//        logger.removeAllAppenders();
//        logger.addAppender(rollingFileAppender);
//    }

    /**
     * 构造函数
     *
     * @param url          请求地址
     * @param method       请求类型
     * @param requestQueue 网络请求队列
     */
    public AppRequest(String url, int method, RequestQueue requestQueue) {
        super(url, method, requestQueue);
    }

    /**
     * 通过NDS服务器解析得到IP
     *
     * @return
     */
    private List<String> getIpFromDnsServer() {
        try {
            String domain = new URL(getUrl()).getHost();
            if (Utils.isValidDnsName(domain)) {
                AppLog.i("解析domain, URL:" + getUrl() + ", domain:" + domain);
                return new DNSHelper(AppRequestConst.DNS_SERVERS).resolver(domain);
            } else {
                AppLog.i("解析域名发现无效的域名。" + domain);
                return Collections.EMPTY_LIST;
            }
        } catch (DnsException e) {
            AppLog.i("域名解析出错", e);
            return Collections.EMPTY_LIST;
        } catch (MalformedURLException e) {
            AppLog.i("域名解析出错", e);
            return Collections.EMPTY_LIST;
        }
    }

    /**
     * 使用代理
     *
     * @return
     */
    private boolean useProxy() {
        // Wifi环境下才能走代理
        // 已经设置了代理，就不再走代理解析了
        if (!AppUtils.isWifi() || RestfulUtils.isUseProxy()) {
            return false;
        }

        if (!BaseConfig.IS_USE_DNSPROXY) {
            return false;
        }

        // 504 time out
        List<String> ips = getIpFromDnsServer();
        if (ips.size() > 0) {
            // 使用代理
            RestfulUtils.useProxy(ips.get(0), 80);
            AppLog.i("已解析出域名.");
            return true;
        }
        AppLog.i("没有解析出域名.");
        return false;
    }

    private void printRequestLog() {
        AppLog.i(ErrTag.TAG_HTTP, "resturl = " + getRestfulUrl(getUrl()));
        AppLog.i(ErrTag.TAG_HTTP, "request method:" + getMethod() + " @see Request.Method");
        AppLog.i(ErrTag.TAG_HTTP, "request encoding:" + getParamEncoding());
        AppLog.i(ErrTag.TAG_HTTP, "request params:" + getRequestParams());
        AppLog.i(ErrTag.TAG_HTTP, "request rest:" + getRestfulParams());
        AppLog.i(ErrTag.TAG_HTTP, "request head:" + getHeader());
    }

    private boolean isExpired(HttpRequestException ex) {
        String errMessage = ex.getMessage();
        // 新版过期判断
        boolean errCodeRes = Strings.equalsIgnoreCase("token has expired", errMessage);
        if (errCodeRes) {
            return true;
        } else {
            // 老版过期判断
            String body = ex.getRequest().getBody();
            if (body != null) {
                body = body.toLowerCase();
            }
            return ex.getRequest().getStatusCode() == 402 && body.contains("token has expired");
        }
//        boolean oldRes = errCodeRes ? errCodeRes : ex.getRequest().getStatusCode() == 402 && ex.getRequest().getBody().contains("token has expired");
//        return errCodeRes || oldRes;
    }

    /**
     * 请求数据，如果出现token过期，需要重新登录
     *
     * @return
     * @throws HttpRequestException
     */
    private HttpRequest getHttpRequest() throws HttpRequestException {
        try {
            printRequestLog();
            HttpRequest request = super.request();
            assertTokenExpired();
            return request;
        } catch (HttpRequestException ex) {
            if (isExpired(ex)) {
                AppLog.i("token expired relogin...", ex);
                // 重新登录 老版接口
                if (reLogin()) {
                    AppLog.i("relogin success");
                    putHeader("access_token", AccountUtils.getLoginUser().getAccessToken());
                    return super.request();
                }
            }
            throw ex;
        }
    }

    private HttpRequest getHttpRequestJson() throws HttpRequestException {
        try {
            printRequestLog();
            HttpRequest request = super.requestJson();
            assertTokenExpired();
            return request;
        } catch (HttpRequestException ex) {
            // token过期
            if (isExpired(ex)) {
                AppLog.i("token expired relogin...", ex);
                // 重新登录 老版接口
                if (reLogin()) {
                    AppLog.i("relogin success");
                    putHeader("access_token", AccountUtils.getLoginUser().getAccessToken());
                    return super.requestJson();
                }
            }
            throw ex;
        }
    }

    private void assertTokenExpired() throws HttpRequestException {
        // 判断body中是否包含20132错误码和Invalid token, token has expired信息
        String body = super.getBody();
        if (Strings.isEmpty(body)) {
            return;
        }
        try {
            JSONObject object = new JSONObject(body);
            if (object.getInt("code") == ResponseCode._20132) {
                throw new HttpRequestException("token has expired", new Exception("token has expired"), this);
            }
        } catch (JSONException e) {
            AppLog.w(ErrTag.TAG_HTTP, "warn", e);
        }
    }

    protected boolean reLogin() {
        final Context context = ZxApplication.getApplication();
        if (context == null) {
            AppLog.i("刷新Token失败, content=null");
            return false;
        }
        String loginName = PreferencesUtils.getString(context, AppConst.LOGIN_NAME, null);
        String loginPass = PreferencesUtils.getString(context, AppConst.LOGIN_PASS, null);
        if (loginName == null || loginPass == null) {
            AppLog.i("刷新Token失败, 用户名密码找不到");
            return false;
        }
        try {
//            LoginInfo loginInfo = new UserServiceImpl().login(loginName, loginPass, AppUtils.getDeviceId(context));
//            if (loginInfo == null) {
//                throw new RuntimeException("获取登录信息为null");
//            }
            // 取得StudentId并赋值给AccountId
//            if(loginInfo.getUserInfos() != null && loginInfo.getUserInfos().size() > 0){
//                loginInfo.setStudentId(loginInfo.getUserInfos().get(0).getAccountId());
//            } else {
//                loginInfo.setStudentId(loginInfo.getAccountId());
//            }
            // 登录成功
            AccountUtils.clearLoginUser();
//            AccountUtils.setLoginUser(loginInfo);
//            AppLog.i("刷新Token成功, token=" + loginInfo.getAccess_token());
            return true;
        } catch (Exception e) {
            AppLog.i("刷新Token失败", e);

            // 清空
            AccountUtils.clear();
            // 通知所有页面Finish
            context.sendBroadcast(new Intent(RoboForActionBarActivity.ACTION));
            // 退出登录
            MobclickAgent.onProfileSignOff();

            // 跳转到登录页面
            //TODO
            //TODO

//            Intent intent = new Intent(context, LoginActivity.class);
//            intent.putExtra(LoginActivity.MESSAGE, "登录已过期,请重新登录");
//            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//            context.startActivity(intent);
            return false;
        }
    }

    @Override
    public HttpRequest request() throws HttpRequestException {
        try {
            return getHttpRequest();
        } catch (HttpRequestException ex) {
            // 出现异常，通过解析NDS，设置代理去访问一次
            if (useProxy()) {
                // 再请求一次
                return getHttpRequest();
            }
            throw ex;
        }
    }

    @Override
    public HttpRequest requestJson() throws HttpRequestException {
        try {
            return getHttpRequestJson();
        } catch (HttpRequestException ex) {
            // 出现异常，通过解析NDS，设置代理去访问一次
            if (useProxy()) {
                // 再请求一次
                return getHttpRequestJson();
            }
            throw ex;
        }
    }

    //存在漏洞，获取全部请使用 getFullBody()    仅获取返回结果的data下面的内容，请调用 getDataBody()
    @Deprecated
    @Override
    public String getBody() {
        String body = super.getBody();
        if (TextUtils.isEmpty(body)) {
            return "body is null";
        }
        AppLog.i(ErrTag.TAG_HTTP, "getFullBody = " + body);
        try {
            JSONObject object = new JSONObject(body);
            if (object.has("code") && object.has("data")) {
                if (object.getInt("code") != ResponseCode._10000) {
                    // 非10000抛出异常
                    AppLog.w(ErrTag.TAG_HTTP, "request failure " + getUrl() + " res " + body);
                    AppRequestException exception = new AppRequestException(getInternalResult(new TypeToken<HttpResponse<RESULT>>() {
                    }));
                    throw exception;
                }
                return object.getString("data");
            } else {
                AppRequestException exception = new AppRequestException(getInternalResult(new TypeToken<HttpResponse<RESULT>>() {
                }));
                throw exception;
            }
        } catch (Exception e) {
            AppLog.i(e.getMessage(), e);
            throw new AppRequestException(getInternalResult(new TypeToken<HttpResponse<RESULT>>() {
            }));
        }
    }

    public String getDataBody() throws JSONException, AppRequestException {
        String body = super.getBody();
        if (TextUtils.isEmpty(body)) {
            throw new JSONException("body is null");
        }
        JSONObject object = new JSONObject(body);
        if (object.has("code")) {
            if (object.getInt("code") != ResponseCode._10000) {
                // 非10000抛出异常
                AppLog.w(ErrTag.TAG_HTTP, "request failure " + getUrl() + " res " + body);
                AppRequestException exception = new AppRequestException(getInternalResult(new TypeToken<HttpResponse<RESULT>>() {
                }));
                throw exception;
            }

            return object.getString("data");
        } else {
            throw new JSONException("code is null");
        }
    }

    private HttpResponse<RESULT> getInternalResult(TypeToken<HttpResponse<RESULT>> token) {
        return new Gson().fromJson(super.getBody(), token.getType());
    }

    /**
     * 获取全部body内容
     *
     * @return
     */
    public String getFullBody() {
        return super.getBody();
    }

    /**
     * 返回指定的实体对象
     *
     * @param entityClass
     * @param <T>
     * @return
     *//*
    @Override
    public <T> T getResult(Class<T> entityClass) {
        return fromJson(entityClass, getBody());
    }

    @Override
    public <TYPE> TYPE getResult(TypeToken<TYPE> token) {
        return new Gson().fromJson(getBody(), token.getType());
    }*/

}
